﻿using Furion.DataEncryption.Extensions;
using Masuit.Tools.Security;
using Microsoft.Extensions.Caching.Memory;
using PMP.Application.Models;
using PMP.Core.Entities;
using PMP.Core.Enums;
using PMP.Core.Extensions;
using PMP.Core.SignalR;
using PMP.Core.SqlSugar;

namespace PMP.Application.Apis;

/// <summary>
/// 用户管理
/// </summary>
public class AccountApi: IDynamicApiController
{
    private readonly Repository<TbAccount> _userRepo;
    private readonly IMemoryCache _memoryCache;
    private readonly MsgHub _msgHub;
    
    public AccountApi(IMemoryCache memoryCache
        , Repository<TbAccount> userRepo
        , MsgHub msgHub)
    {
        _memoryCache = memoryCache;
        _userRepo = userRepo;
        _msgHub = msgHub;
    }

    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<TbAccount> Get(int id)
    {
        var user = await DbContext.Instance.Queryable<TbAccount>()
            .Includes(a => a.Attachments)
            .Where(a => a.Id == id)
            .SingleAsync();
        return user;
    }
    
    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <param name="realName"></param>
    /// <returns></returns>
    public async Task<TbAccount> GetByRealName(string realName)
    {
        var user = await DbContext.Instance.Queryable<TbAccount>()
            .Includes(a => a.Attachments)
            .Where(a => a.RealName == realName)
            .SingleAsync();
        return user;
    }

    /// <summary>
    /// 获取用户列表
    /// </summary>
    /// <returns></returns>
    public async Task<List<TbAccount>> GetList()
    {
        var list = await _userRepo.GetListAsync();
        return list;
    }
    
    /// <summary>
    /// 获取用户列表
    /// </summary>
    /// <returns></returns>
    public async Task<Page<TbAccount>> GetPage([FromForm]int pageIndex,[FromForm]int pageSize)
    {
        var list = await _userRepo.GetPageAsync(pageIndex,pageSize);
        return list;
    }
    
    /// <summary>
    /// 添加/修改用户
    /// </summary>
    /// <param name="param"></param>
    /// <param name="files">附件</param>
    /// <returns></returns>
    [AllowAnonymous]
    public async Task<int> AddOrUpdate( AccountModifyParam param)
    {
        var model = param.Adapt<TbAccount>();
        model.Password = param.Password.ToMD5Encrypt();
        if(model.Id == 0)
        {
            if (!string.IsNullOrWhiteSpace(param.InvitationCode))
            {
                var isStr = param.InvitationCode.AESDecrypt("");
                if (int.TryParse(isStr, out var userId))
                {
                    var account = await DbContext.Instance.Queryable<TbAccount>()
                        .Where(a => a.Id == userId)
                        .FirstAsync();
                    if (account == null)
                        throw Oops.Bah("邀请码有误");
                    model.ReferrerUserId = userId;
                }
                else
                {
                    throw Oops.Bah("邀请码有误");
                }
            }
            else
            {
                model.ReferrerUserId = App.User.GetUserId();
            }
            model = await DbContext.Instance.Insertable(model).ExecuteReturnEntityAsync();
        }
        else
        {
            await DbContext.Instance.Updateable(model)
                .IgnoreNullColumns()
                .ExecuteCommandAsync();
        }

        return model.Id;
    }

    /// <summary>
    /// 上传附件
    /// </summary>
    /// <param name="accountId"></param>
    /// <param name="files"></param>
    public async Task AddAttachment([FromForm]int accountId,[FromForm]List<IFormFile> files)
    {
        // 附件
        var attachments = new List<TbAccountAttachment>();
        if (files?.Any() == true)
        {
            var folder  = "./Files/AccountAttachment/" ;
            Directory.CreateDirectory(folder);
            foreach (var file in files)
            {
                var filePath = $"{folder}{file.FileName}";
                await using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }
                var attachment = new TbAccountAttachment
                {
                    AccountId = accountId,
                    FileName = file.FileName,
                    FilePath = filePath
                };
                attachments.Add(attachment);
            }
        }
        await DbContext.Instance.Insertable(attachments).ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除附件
    /// </summary>
    /// <param name="attachmentId"></param>
    public async Task DeleteAttachment([FromForm]int attachmentId)
    {
        await DbContext.Instance.Deleteable<TbAccountAttachment>()
            .Where(a => a.Id == attachmentId)
            .ExecuteCommandAsync();
    }

    /// <summary>
    /// 获取响应时间
    /// </summary>
    /// <param name="accountId">用户id，不填不限制</param>
    /// <returns></returns>
    public async Task<int?> GetResponseTime([FromForm] int? accountId)
    {
        var seconds = await DbContext.Instance.Queryable<TbNotification>()
            .WhereIF(accountId.HasValue, a => a.CreateUserId == accountId)
            .Where(a => a.IsDeal == true)
            .Select(a => SqlFunc.DateDiff(DateType.Second, a.CreateTime, (DateTime) a.DealTime))
            .ToListAsync();
        if (seconds.Count == 0) return 0;
        return (int)seconds.Average(a=>a);
    }

    /// <summary>
    /// 获取项目推荐数
    /// </summary>
    /// <param name="accountId">创建人/负责人id，不填不限制</param>
    /// <returns></returns>
    public async Task<int> GetRecommendedProjectCount([FromForm] int? accountId)
    {
        var count = await DbContext.Instance.Queryable<TbProject>()
            .WhereIF(accountId.HasValue, a => a.CreateUserId == accountId || a.ResponsibleUserId == accountId)
            .Where(a => a.CreateUserId == App.User.GetUserId())
            .CountAsync();
        return count;
    }

    /// <summary>
    /// 获取项目达成率
    /// </summary>
    /// <param name="accountId">创建人/负责人id，不填不限制</param>
    /// <returns></returns>
    public async Task<double> GetProjectFinishedRate([FromForm] int? accountId)
    {
        var count1 = await DbContext.Instance.Queryable<TbProject>()
            .WhereIF(accountId.HasValue, a => a.CreateUserId == accountId || a.ResponsibleUserId == accountId)
            .CountAsync();
        if (count1 == 0) return 0;

        var count2 = await DbContext.Instance.Queryable<TbProject>()
            .WhereIF(accountId.HasValue, a => a.CreateUserId == accountId)
            .Where(a => a.IsFinished == true).CountAsync();
        return count2 * 1.0 / count1;
    }
    
    /// <summary>
    /// 获取用户评分
    /// </summary>
    /// <param name="accountId">用户id</param>
    /// <param name="year">年份</param>
    /// <returns></returns>
    public async Task<TbAccountScore> GetScore([FromForm] int accountId,[FromForm]int year)
    {
        var res =await ScoreHelper.GetAndUpdateScore(accountId, year);
        return res;
    }

    /// <summary>
    /// 获取本人及子用户的人员提级申请数
    /// </summary>
    /// <param name="accountId"></param>
    /// <returns></returns>
    public async Task<int> GetUpgradeCount(int accountId)
    {
        var count = await DbContext.Instance.Queryable<TbAccountUpgrade>()
            .RightJoin<TbAccount>((u, a) => u.AccountId == a.Id)
            .Where((u, a) => a.ReferrerUserId == accountId || a.Id == accountId)
            .CountAsync();
        return count;
    }

    /// <summary>
    /// 提级申请
    /// </summary>
    /// <param name="accountId">被提级人员</param>
    /// <param name="reason">理由</param>
    /// <exception cref="AppFriendlyException"></exception>
    public async Task UpgradeApply([FromForm] int accountId, [FromForm] string reason)
    {
        var accounts = await DbContext.Instance.Queryable<TbAccount>()
            .Where(a => new int[] {accountId, App.User.GetUserId()}.Contains(a.Id) || a.IsSuperAdmin == true)
            .ToListAsync();
        if (!accounts.Any(a => a.Id == accountId))
            throw Oops.Bah("未找到该用户。");

        var targetAccount = accounts.First(a => a.Id == accountId);
        if(targetAccount.UserLevel == EnumUserLevel.Level2)
            throw Oops.Bah("该用户已经是管理合伙人。");
        
        var operatorUser = accounts.Find(a => a.IsSuperAdmin == true);
        var operatorId = accounts.Find(a=>a.Id == App.User.GetUserId())?.ReferrerUserId ?? 0;
        if (operatorId != 0)
        {
           var operatorUser1 = await DbContext.Instance.Queryable<TbAccount>()
                .Where(a => a.Id == operatorId).SingleAsync();
           if (operatorUser1 != null)
           {
               operatorUser = operatorUser1;
           }
        }
            
        var upgrade = new TbAccountUpgrade
        {
            AccountId = accountId,
            AccountName = targetAccount.RealName,
            OperatorId = operatorUser.Id,
            OperatorName = operatorUser.RealName,
            UpgradeLevel = targetAccount.UserLevel+1,
            Reason = reason,
        };
        upgrade = await DbContext.Instance.Insertable(upgrade).ExecuteReturnEntityAsync();
        await _msgHub.SendAccountUpgradeNotify(upgrade.OperatorId, upgrade.Id, $"{upgrade.AccountName}的提级申请需要您处理。");
    }
    
    /// <summary>
    /// 获取需某人处理的提级申请
    /// </summary>
    /// <param name="accountId">需哪个用户处理（null：全部）</param>
    /// <param name="isProcessed">是否已处理（null：全部）</param>
    /// <returns></returns>
    public async Task<List<TbAccountUpgrade>> GetUpgradeList([FromForm]int? accountId,[FromForm]bool? isProcessed)
    { 
        var res = await DbContext.Instance.Queryable<TbAccountUpgrade>()
            .WhereIF(accountId.HasValue, a => a.OperatorId == accountId)
            .WhereIF(isProcessed.HasValue, a => a.IsAgree != null)
            .WhereIF(!isProcessed.HasValue, a => a.IsAgree == null)
            .ToListAsync();
        return res;
    }

    /// <summary>
    /// 处理提级申请
    /// </summary>
    /// <param name="upgradeId">提级申请id</param>
    /// <param name="reason">原因</param>
    /// <param name="isAgree">是否通过</param>
    /// <exception cref="AppFriendlyException"></exception>
    public async Task ProcessUpgradeApply([FromForm] int upgradeId, [FromForm] string reason, [FromForm] bool isAgree)
    {
        
        var upgrade = await DbContext.Instance.Queryable<TbAccountUpgrade>()
            .Where(a => a.Id == upgradeId)
            .SingleAsync();
        if (upgrade == null)
            throw Oops.Bah("没有找到该提级申请。");
        
        upgrade.IsAgree = isAgree;
        upgrade.Reason = reason;
        upgrade.UpdateUserId = App.User.GetUserId();
        upgrade.UpdateTime = DateTime.Now;
        var loginUser = await DbContext.Instance.Queryable<TbAccount>()
            .Where(a => a.Id == App.User.GetUserId())
            .FirstAsync();
        await DbContext.Instance.Updateable<TbAccountUpgrade>(upgrade).ExecuteCommandAsync();
        if (loginUser.IsSuperAdmin && isAgree)
        {
            // 到超级管理员的话，就是最后一个审批，通过后直接提级
            await DbContext.Instance.Updateable<TbAccount>()
                .SetColumns(a => new ()
                {
                    UserLevel = upgrade.UpgradeLevel,
                    UserLevelUpdateTime = DateTime.Now
                })
                .Where(a => a.Id == upgrade.AccountId)
                .ExecuteCommandAsync();
        }
        else if(isAgree)
        {
            await UpgradeApply(upgrade.AccountId, "同意提级，请上级处理。");
        }

        await DbContext.Instance.Updateable<TbNotification>()
            .SetColumns(a=>new TbNotification{IsDeal = true,UpdateTime = DateTime.Now,UpdateUserId = App.User.GetUserId()})
            .Where(a => a.Token == SignalRToken.AccountUpgrade)
            .Where(a => a.TargetUserId == App.User.GetUserId())
            .Where(a => a.AccountUpgradeId == upgradeId)
            .ExecuteCommandAsync();

    }

    /// <summary>
    /// 获取邀请码
    /// </summary>
    /// <returns></returns>
    public string GetInvitationCode()
    {
        var code = App.User.GetUserId().ToString().AESEncrypt("");
        return code;
    }

    /// <summary>
    /// 获取下级用户列表
    /// </summary>
    /// <param name="parentUserId">上级用户id</param>
    /// <returns></returns>
    public async Task<List<SubordinateUserResponse>> GetSubordinateUsers(int parentUserId)
    {
        var allUser = await DbContext.Instance.Queryable<TbAccount>()
            .ToListAsync();
        var resUser = allUser.Where(a => a.ReferrerUserId == parentUserId)
            .ToList();
        var scoreList = await DbContext.Instance.Queryable<TbAccountScore>()
            .Where(a => resUser.Select(a => a.Id).Contains(a.AccountId))
            .Where(a => a.Year == DateTime.Today.Year)
            .ToListAsync();
        var list = new List<SubordinateUserResponse>();
        foreach (var user in resUser)
        {
            var item = user.Adapt<SubordinateUserResponse>();
            item.Score = scoreList.FirstOrDefault(a => a.AccountId == user.Id)?.TotalScore ?? 0;
            item.ReferrerUserName = allUser.FirstOrDefault(a => a.Id == user.ReferrerUserId)?.RealName ?? "";
            // item.SuperiorUserName = allUser.FirstOrDefault(a => a.Id == user.SuperiorUserId)?.RealName ?? "";
            list.Add(item);
        }
        return list;
    }
}